package com.ubi.core.framework.request;

import com.ubi.core.framework.GlobalConfig;
import com.ubi.core.utils.AssertUtils;
import org.apache.commons.io.IOUtils;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 包装原始的HttpServletRequest,并且提前加载request body customHeaders为重写header中的Map时使用
 */
public class RequestWrapper extends HttpServletRequestWrapper {

    private RequestCachingInputStream requestCachingInputStream;

    private String requestBody;

    // holds custom header and value mapping
    private final Map<String, String> customHeaders;

    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        if (shouldPreLoadRequestBody(request)) {
            preLoadRequestBody(request);
        }
        this.customHeaders = new HashMap<>();
    }

    private boolean shouldPreLoadRequestBody(HttpServletRequest request) {
        if (request.getContentType() != null && request.getContentType().startsWith("multipart/")) {
            return false;
        }
        return !(!"POST".equalsIgnoreCase(request.getMethod()) && !"PUT".equalsIgnoreCase(request.getMethod()));
    }

    private void preLoadRequestBody(HttpServletRequest request) throws IOException {
        AssertUtils.assertNotNull(request.getInputStream(), " request input stream should not be null");
        requestBody = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
        requestCachingInputStream = new RequestCachingInputStream(requestBody.getBytes(GlobalConfig.CHARSET_UTF8));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (requestCachingInputStream != null) {
            return requestCachingInputStream;
        }
        return super.getInputStream();
    }

    public String getRequestBody() {
        return requestBody;
    }

    public void putHeader(String name, String value) {
        this.customHeaders.put(name, value);
    }

    public String getHeader(String name) {
        // check the custom headers first
        String headerValue = customHeaders.get(name);

        if (headerValue != null) {
            return headerValue;
        }
        // else return from into the original wrapped object
        return ((HttpServletRequest) getRequest()).getHeader(name);
    }

    public Enumeration<String> getHeaderNames() {
        // create a set of the custom header names
        Set<String> set = new HashSet<>(customHeaders.keySet());

        // now add the headers from the wrapped request object
        Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaderNames();
        while (e.hasMoreElements()) {
            // add the names of the request headers into the list
            String n = e.nextElement();
            set.add(n);
        }

        // create an enumeration from the set and return
        return Collections.enumeration(set);
    }

}
